Skip to content

Allowlist registry redirect targets for private registries - #341

Merged
v-abhishekbhaskar merged 2 commits into
mainfrom
abhishekbhaskar/egress-redirect-targets
Oct 26, 2026
Merged

v-abhishekbhaskar merged 2 commits into
mainfrom
abhishekbhaskar/egress-redirect-targets

Conversation

@v-abhishekbhaskar

Copy link
Copy Markdown
Contributor

What are you trying to accomplish?

Self-hosted JFrog Artifactory instances redirect package downloads to presigned URLs on the customer's own S3 bucket (jfrog-prod-<id>.s3.amazonaws.com). The egress allowlist covers JFrog's shared regional buckets but not these per-instance ones, and the bucket name can't be derived from the registry host. So with egress enforcement on, downloads fail even though the index lookups work.

This PR adds EgressAllowlistHandler.HandleResponse. When one of the job's private registries returns a redirect, the proxy allows the redirect's exact HTTPS destination host for the rest of the job.

Anything you want to highlight for special attention from reviewers?

  • Which redirects are trusted: only those from credential hosts that are not already on the static allowlist. Public registries and GitHub hosts are excluded because users can publish content there.
  • What is learned: only the exact hostname of an https target. IP addresses are never learned, and sibling or parent hosts stay blocked.
  • Alternatives considered: hard-coding each customer's bucket in the YAML doesn't scale. A jfrog-prod-*.s3.amazonaws.com wildcard is unsafe because anyone can register a bucket with a matching name. Following the actual redirect relies on a registry the job already trusts.
  • Caching and concurrency: cached 3xx responses go through the same response hook, so they are handled too. The learned-host set is protected by an RWMutex.

How will you know you've accomplished your goal?

  • New end-to-end test TestProxyEgressAllowlistEnforceAllowsPrivateRegistryRedirectTarget: the bucket returns 403 before the redirect. A download from the registry then follows the redirect and gets 200, with no credential sent to the bucket. Other hosts stay blocked.
  • New unit tests: cover the rejected cases (redirects from hosts that aren't credential hosts, public or GitHub hosts, non-3xx responses, http targets, IP addresses, and a missing Location).
  • Commands:
    • go test -race -count=1 ./...: passed.
    • golangci-lint: not run; it isn't installed locally.

Checklist

  • I have run the complete test suite to ensure all tests and linters pass.
  • I have thoroughly tested my code changes to ensure they work as expected, including adding additional tests for new functionality.
  • I have written clear and descriptive commit messages.
  • I have provided a detailed description of the changes in the pull request, including the problem it addresses, how it fixes the problem, and any relevant details about the implementation.
  • I have ensured that the code is well-documented and easy to understand.

@v-abhishekbhaskar v-abhishekbhaskar self-assigned this Oct 26, 2026
@v-abhishekbhaskar
v-abhishekbhaskar requested a review from a team as a code owner October 26, 2026 22:51
Copilot AI balanced review requested due to automatic review settings October 26, 2026 22:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Redirect learning trusts plaintext source responses and misses redirects returned by later authentication retries.

2 open issues
What changed in this PR

This PR extends the proxy’s egress allowlist to support private registries that redirect downloads to customer-specific storage hosts, without adding broad static allowlist entries.

Changes:

  • Learn exact HTTPS destination hostnames from eligible registry redirects.
  • Protect learned hosts with a mutex and register a response hook.
  • Add unit and end-to-end coverage for redirect learning and rejected destinations.
File Description
proxy.go Registers the egress allowlist response hook.
proxy_test.go Tests redirected downloads, credential isolation, and continued blocking of unrelated hosts.
internal/​handlers/​egress_allowlist.go Adds redirect-source filtering and synchronized destination learning.
internal/​handlers/​egress_allowlist_test.go Tests exact-host learning and rejection cases.

Review effort: Balanced

Comment thread internal/handlers/egress_allowlist.go
Comment thread proxy.go Outdated
@v-abhishekbhaskar
v-abhishekbhaskar force-pushed the abhishekbhaskar/egress-redirect-targets branch from 2b80dfd to bb8f9bb Compare October 26, 2026 23:12
@v-sachin-sandhu

Copy link
Copy Markdown

For reference

Reviewed PR: , no serious privacy or security issues. It only learns exact HTTPS hostnames from non-public private-registry redirects, never IPs, sends no credentials to learned hosts, and logs only the host.
Residual low risks: trust is job-wide, learned hosts are allowed on any port or scheme, shared S3 hostnames, and the learned-host map is unbounded.
Suggested hardening: scope to port 443, cap entries, and optionally add a TTL.

@v-abhishekbhaskar
v-abhishekbhaskar merged commit bdec1ee into main Oct 26, 2026
109 of 112 checks passed
@v-abhishekbhaskar
v-abhishekbhaskar deleted the abhishekbhaskar/egress-redirect-targets branch October 26, 2026 23:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants